package cn.hpclub.server.util;


import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 根据环境变量env加载文件(-Denv=test)，从类路径下寻找，首先寻找classpath:config.name-${env}.ext，没找到就寻找${env}/config.name.ext，再没找到就找config.name.ext。
 * 没有设置env环境变量的时候，给什么路径就从什么路径找
 */
public class PropertiesUtils {
    private static Prop prop = null;
    private static final Map<String, Prop> map = new HashMap<String, Prop>();

    private PropertiesUtils() {}

    /**
     * Using the properties file. It will loading the properties file if not loading.
     * @see #use(String, String)
     */
    public static Prop use(String fileName) {
        return use(fileName, "UTF-8");
    }

    /**
     * Using the properties file. It will loading the properties file if not loading.
     * <p>
     * Example:<br>
     * PropertiesUtils.use("config.txt", "UTF-8");<br>
     * PropertiesUtils.use("other_config.txt", "UTF-8");<br><br>
     * String userName = PropertiesUtils.get("userName");<br>
     * String password = PropertiesUtils.get("password");<br><br>
     *
     * userName = PropertiesUtils.use("other_config.txt").get("userName");<br>
     * password = PropertiesUtils.use("other_config.txt").get("password");<br><br>
     *
     * PropertiesUtils.use("com/jfinal/config_in_sub_directory_of_classpath.txt");
     *
     * @param fileName the properties file's name in classpath or the sub directory of classpath
     * @param encoding the encoding
     */
    public static Prop use(String fileName, String encoding) {
        Prop result = map.get(fileName);
        if (result == null) {
            synchronized (map) {
                result = map.get(fileName);
                if (result == null) {
                    result = new Prop(fileName, encoding);
                    map.put(fileName, result);
                    if (PropertiesUtils.prop == null)
                        PropertiesUtils.prop = result;
                }
            }
        }
        return result;
    }

    /**
     * Using the properties file bye File object. It will loading the properties file if not loading.
     * @see #use(File, String)
     */
    public static Prop use(File file) {
        return use(file, "UTF-8");
    }

    /**
     * Using the properties file bye File object. It will loading the properties file if not loading.
     * <p>
     * Example:<br>
     * PropertiesUtils.use(new File("/var/config/my_config.txt"), "UTF-8");<br>
     * Strig userName = PropertiesUtils.use("my_config.txt").get("userName");
     *
     * @param file the properties File object
     * @param encoding the encoding
     */
    public static Prop use(File file, String encoding) {
        Prop result = map.get(file.getName());
        if (result == null) {
            synchronized (map) {
                result = map.get(file.getName());
                if (result == null) {
                    result = new Prop(file, encoding);
                    map.put(file.getName(), result);
                    if (PropertiesUtils.prop == null)
                        PropertiesUtils.prop = result;
                }
            }
        }
        return result;
    }

    public static Prop useless(String fileName) {
        Prop previous = map.remove(fileName);
        if (PropertiesUtils.prop == previous)
            PropertiesUtils.prop = null;
        return previous;
    }

    public static void clear() {
        prop = null;
        map.clear();
    }

    public static Prop getProp() {
        if (prop == null)
            throw new IllegalStateException("Load propties file by invoking PropertiesUtils.use(String fileName) method first.");
        return prop;
    }

    public static Prop getProp(String fileName) {
        return map.get(fileName);
    }

    public static String get(String key) {
        return getProp().get(key);
    }

    public static String get(String key, String defaultValue) {
        return getProp().get(key, defaultValue);
    }

    public static Integer getInt(String key) {
        return getProp().getInt(key);
    }

    public static Integer getInt(String key, Integer defaultValue) {
        return getProp().getInt(key, defaultValue);
    }

    public static Long getLong(String key) {
        return getProp().getLong(key);
    }

    public static Long getLong(String key, Long defaultValue) {
        return getProp().getLong(key, defaultValue);
    }

    public static Boolean getBoolean(String key) {
        return getProp().getBoolean(key);
    }

    public static Boolean getBoolean(String key, Boolean defaultValue) {
        return getProp().getBoolean(key, defaultValue);
    }

    public static boolean containsKey(String key) {
        return getProp().containsKey(key);
    }


    public static class Prop{
        private static final String env = System.getProperty("env");//环境
        private Properties properties;

        public Prop(String fileName) {
            this(fileName, "UTF-8");
        }

        public Prop(String fileName, String encoding) {
            this.properties = null;
            InputStream inputStream = null;

            try {
                inputStream = EnvProp.loadEnvInputStream(fileName);
                this.properties = new Properties();
                this.properties.load(new InputStreamReader(inputStream, encoding));
            } catch (IOException var12) {
                throw new RuntimeException("Error loading properties file.", var12);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException var11) {
                        var11.printStackTrace();
                    }
                }

            }

        }

        public Prop(File file) {
            this(file, "UTF-8");
        }

        public Prop(File file, String encoding) {
            this.properties = null;
            if (file == null) {
                throw new IllegalArgumentException("File can not be null.");
            } else if (!file.isFile()) {
                throw new IllegalArgumentException("File not found : " + file.getName());
            } else {
                FileInputStream inputStream = null;

                try {
                    inputStream = new FileInputStream(file);
                    this.properties = new Properties();
                    this.properties.load(new InputStreamReader(inputStream, encoding));
                } catch (IOException var12) {
                    throw new RuntimeException("Error loading properties file.", var12);
                } finally {
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException var11) {
                            var11.printStackTrace();
                        }
                    }

                }

            }
        }

        public String get(String key) {
            return this.properties.getProperty(key);
        }

        public String get(String key, String defaultValue) {
            return this.properties.getProperty(key, defaultValue);
        }

        public Integer getInt(String key) {
            return this.getInt(key, (Integer)null);
        }

        public Integer getInt(String key, Integer defaultValue) {
            String value = this.properties.getProperty(key);
            return value != null ? Integer.parseInt(value) : defaultValue.intValue();
        }

        public Long getLong(String key) {
            return this.getLong(key, (Long)null);
        }

        public Long getLong(String key, Long defaultValue) {
            String value = this.properties.getProperty(key);
            return value != null ? Long.parseLong(value) : defaultValue.longValue();
        }

        public Boolean getBoolean(String key) {
            return this.getBoolean(key, (Boolean)null);
        }

        public Boolean getBoolean(String key, Boolean defaultValue) {
            String value = this.properties.getProperty(key);
            return value != null ? Boolean.parseBoolean(value) : defaultValue.booleanValue();
        }

        public boolean containsKey(String key) {
            return this.properties.containsKey(key);
        }

        public Properties getProperties() {
            return this.properties;
        }
    }

    public static void main(String[] args) {
        PropertiesUtils.Prop prop = PropertiesUtils.use("jdbc.properties");
        System.out.println(prop.get("filters"));
    }
}

